#include "libORCL/ORCL.h"
#include "libORCL/ORCL_size.h"
#include <getopt.h>

int main(int argc,char** argv){

    // 服务器编号
    int server_num = -1;

    static struct option opts[] = {
        {"server_num", required_argument, 0, 'n'},
    };

    while (1){
        int c = getopt_long(argc, argv, "n:", opts, NULL);

        if (c == -1)
        {
            break;
        }

        switch (c){
            case 'n':
                server_num = atoi(optarg);
                break;
            
            default:
                printf("Invalid argument %d\n", c);
                assert(false);
        }
    }

    assert(server_num>=0);

    // 解析参数，我们现在只加入一个参数就是节点编号，两个进程分布在两个节点上
    int port_index;
    int numa_id;

    // 0和3在0号端口上，1和2在1号端口上
    if(server_num == 0 || server_num == 3){
        port_index = 0; 
        numa_id = 1;
    }else{
        port_index = 1; 
        numa_id = 0;
    }

    // 每组的数量
    int group_size = 2;
    // 当前组号，0、1在0组，2、3在1组
    int group_id = server_num / group_size;

    // 下面进行连接
    // 测试一下初始化
    struct orcl_context* orcl_ctx = orcl_context_init(server_num,group_id,4,2,group_size,1,port_index,numa_id,NULL,M_2,16*server_num+1,NULL,0);

    // 初始化一下缓冲区
    memset((void *)orcl_ctx->message_buffer, 0, orcl_ctx->message_buffer_size);

    // 测试之前等待
    sleep(2);

    // 测试forward转发的功能，引入4个进程，0、1、2、3，分别在两个网卡上
    // port_index0:0、3    port_index1:1、2
    // 0、1是一组，2、3是一组，我们将forward数据从0发到3
    // 考验转发的能力
    if(server_num == 0){
        
        // 接收的位置
        struct orcl_message_header header;
        header.magic = 'a';
        header.node_id = 3;
        header.offset = 0;
        header.size = 256;
        
        char *buf = (char *)orcl_ctx->message_buffer;
        
        // 将数据到buf的0号位置
        memcpy((void *)&buf[0], &header, sizeof(header));

        // 发送测试
        // 这里执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);

        // 多次执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);

        sleep(3);
        orcl_publish_ready("finish1");

    }else{
        orcl_wait_till_ready("finish1");
    }

    // 查看一下3号节点的缓冲区是不是有数据
    if(server_num == 3){
        volatile char *buf = (volatile char *)orcl_ctx->message_buffer;

        if(buf[0] == 'a'){
            printf("发送成功\n");
        }else{
            printf("发送失败,%d\n", buf[0]);
        }
    }
    
    if(server_num == 0){
        int i;

        for(i = 0; i < 65536; i++){
            // 摇两个随机数，一个是size，一个是offset
            uint64_t seed = 0xdeadbeef;
            // 这是随机数
            int j;
            for (j = 0; j < server_num * 1000000; j++)
            {
                // 一个血妈神奇的随机数生成机制，最后生成的随机数要放在seed中
                orcl_fastrand(&seed);
            }

            int _size = (int)(orcl_fastrand(&seed) % (512 - sizeof(struct orcl_message_header)) + 1);
            int _offset = (int)((orcl_fastrand(&seed) % (orcl_ctx->message_buffer_size - _size)) / 512) * 512;

            struct orcl_message_header header;
            header.magic = 'a';
            header.node_id = 3;
            header.offset = _offset;
            header.size = _size + sizeof(header);

            memcpy((void *)(orcl_ctx->message_buffer + _offset), &header, sizeof(header));

            orcl_write_message_to_remote(orcl_ctx, _offset);
        }
        
        sleep(1);

        // 批量完成之后
        printf("批量发送结束\n");
        orcl_publish_ready("finish2");
    }else{
        orcl_wait_till_ready("finish2");
    }

    // 不用转发的组间发送
    if(server_num == 0){
        
        // 接收的位置
        struct orcl_message_header header;
        header.magic = 'a';
        header.node_id = 2;
        header.offset = 0;
        header.size = 256;
        
        volatile char *buf = (volatile char *)orcl_ctx->message_buffer;
        
        // 将数据到buf的0号位置
        memcpy((void *)&buf[0], &header, sizeof(header));

        // 发送测试
        // 这里执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);

        // 多次执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);

        sleep(3);
        orcl_publish_ready("finish3");

    }else{
        orcl_wait_till_ready("finish3");
    }

    // 查看一下3号节点的缓冲区是不是有数据
    if(server_num == 3 || server_num == 2){
        volatile char *buf = (volatile char *)orcl_ctx->message_buffer;

        if(buf[0] == 'a'){
            printf("发送成功\n");
        }else{
            printf("发送失败,%d\n", buf[0]);
        }
    }

    // 对2号节点进行批量发送
    if(server_num == 0){
        int i;

        for(i = 0; i < 65536; i++){
            // 摇两个随机数，一个是size，一个是offset
            uint64_t seed = 0xdeadbeef;
            // 这是随机数
            int j;
            for (j = 0; j < server_num * 1000000; j++)
            {
                // 一个血妈神奇的随机数生成机制，最后生成的随机数要放在seed中
                orcl_fastrand(&seed);
            }

            int _size = (int)(orcl_fastrand(&seed) % (512 - sizeof(struct orcl_message_header)) + 1);
            int _offset = (int)((orcl_fastrand(&seed) % (orcl_ctx->message_buffer_size - _size)) / 512) * 512;

            struct orcl_message_header header;
            header.magic = 'a';
            header.node_id = 2;
            header.offset = _offset;
            header.size = sizeof(header) + _size;

            memcpy((void *)(orcl_ctx->message_buffer + _offset), &header, sizeof(header));

            orcl_write_message_to_remote(orcl_ctx, _offset);
        }
        
        sleep(1);

        // 批量完成之后
        printf("批量发送结束\n");
        orcl_publish_ready("finish4");
    }else{
        orcl_wait_till_ready("finish4");
    }

    // 针对1号节点进行发送，查看正确性
    if(server_num == 0){
        
        // 接收的位置
        struct orcl_message_header header;
        header.magic = 'a';
        header.node_id = 1;
        header.offset = 0;
        header.size = 256;
        
        volatile char *buf = (volatile char *)orcl_ctx->message_buffer;
        
        // 将数据到buf的0号位置
        memcpy((void *)&buf[0], &header, sizeof(header));

        // 发送测试
        // 这里执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);

        // 多次执行发送
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);
        
        orcl_write_message_to_remote(orcl_ctx, 0);

        sleep(3);
        orcl_publish_ready("finish6");

    }else{
        orcl_wait_till_ready("finish6");
    }

    // 查看一下1号节点的缓冲区是不是有数据
    if(server_num == 1){
        volatile char *buf = (volatile char *)orcl_ctx->message_buffer;

        if(buf[0] == 'a'){
            printf("发送成功\n");
        }else{
            printf("发送失败,%d\n", buf[0]);
        }
    }

    // 针对1号节点的批量发送
    if(server_num == 0){
        int i;

        for(i = 0; i < 65536; i++){
            // 摇两个随机数，一个是size，一个是offset
            uint64_t seed = 0xdeadbeef;
            // 这是随机数
            int j;
            for (j = 0; j < server_num * 1000000; j++)
            {
                // 一个血妈神奇的随机数生成机制，最后生成的随机数要放在seed中
                orcl_fastrand(&seed);
            }

            int _size = (int)(orcl_fastrand(&seed) % (512 - sizeof(struct orcl_message_header)) + 1);
            int _offset = (int)((orcl_fastrand(&seed) % (orcl_ctx->message_buffer_size - _size)) / 512) * 512;

            struct orcl_message_header header;
            header.magic = 'a';
            header.node_id = 2;
            header.offset = _offset;
            header.size = sizeof(header) +  _size;

            memcpy((void *)(orcl_ctx->message_buffer + _offset), &header, sizeof(header));

            orcl_write_message_to_remote(orcl_ctx, _offset);
        }
        
        sleep(1);

        // 批量完成之后
        printf("批量发送结束\n");
        orcl_publish_ready("finish10");
    }else{
        orcl_wait_till_ready("finish10");
    }

    return 1;
}